import { nextTick } from 'vue'
import axios from 'axios'
import { useUserStoreHook } from '@/store/modules/user'
import { ElMessage, ElLoading } from 'element-plus'
import { get, merge } from 'lodash-es'
//import { getToken } from './local-storage'

function logout() {
  useUserStoreHook().logout()
  location.reload()
}

const STATUS_CODES = {
  400: 'Request error.',
  401: 'Not authorized, please login first.',
  402: 'Not authorized, please login first.',
  403: 'Rejected by server.',
  404: 'The request not found.',
  408: 'The Request timeout.',
  500: 'The server error.',
  501: 'The service is not implemented.',
  502: 'The getway error.',
  503: 'The server is not ready.',
  504: 'The getway timeout.',
  505: 'HTTP version is not supported.',
}

/**
 * Creates an instance of the axios service with request and response interceptors.
 * The request interceptor modifies the request config.
 * The response interceptor handles different response status codes and errors.
 * @returns {Object} The created axios service instance.
 */
function createService() {
  const service = axios.create()

  // Request interceptor
  service.interceptors.request.use(
    config => {
      if (!config.noLoading) {
        ElLoading.service()
        nextTick(() => {
          ElLoading.service().close()
        })
      }
      const token = useUserStoreHook().token

      config.headers = {
        ...config.headers,
        Authorization: token? `Bearer ${token}` : undefined,
        // 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
        'Content-Type': 'application/json; charset=UTF-8',
      }

      return config
    },
    error => {
      ElMessage.error(error.errMsg || 'Request error')
      return Promise.reject(error)
    },
  )

  // Response interceptor
  service.interceptors.response.use(
    response => {
      const { status, data, config } = response

      // Defines whether the request is successful
      const isSuccess = status === 200 && data?.code === 200
      if (isSuccess) return data.data

      const message = data.msg ?? STATUS_CODES[status]
      if (message && config?.toast) {
        ElMessage({
          type: 'error',
          message,
          center: true,
          duration: 3000,
          onClose: () => {
            if (status === 401) {
              logout()
            }
          },
        })
      } else if (status === 401) {
        logout()
      }
      return Promise.reject(response)
    },
    // Handle response error
    error => {
      console.warn(error)
      let message = ''
      if (error.response) {
        const { status, data } = error.response
        message = data.msg ?? STATUS_CODES[status]
      } else {
        message = 'Network Error.'
      }
      if (message && error.config?.toast) {
        ElMessage({
          type: 'error',
          message,
          center: true,
          duration: 3000,
          onClose: () => {
            if (error.response?.status === 401) {
              logout()
            }
          },
        })
      } else if (error.response?.status === 401) {
        logout()
      }

      // Reject the promise with the error
      return Promise.reject(error)
    },
  )

  // Return the created axios service instance
  return service
}

/**
 * Creates a request function that can be used to make HTTP requests.
 *
 * @param {Object} service - The axios service instance.
 * @returns {Function} - The request function.
 */
function createRequest(service) {
  /**
   * Makes an HTTP request using the provided configuration.
   *
   * @param {Object} config - The configuration for the request.
   * @param {Object} [config.data] - The data to be sent with the request.
   * @returns {Promise} - A promise that resolves to the response data or rejects with an error.
   */
  return function (config) {
    // Default configuration for the request
    const defaultConfig = {
      headers: {
        // Authorization: token ? `Bearer ${token}` : undefined,
        // 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
        'Content-Type': 'application/json; charset=UTF-8',
      },
      timeout: 30000, // Request timeout in milliseconds
      baseURL: import.meta.env.VITE_BASE_API, // Base URL for the API
      data: {}, // Data to be sent with the request
      toast: true, // Whether to show a toast when an error occurs
    }

    // If there is data in the config, generate a unique ID and attach it to the data
    if (config.data) {
      const generateUuid = () => Array.from({ length: 22 }, () => Math.floor(Math.random() * 36).toString(36)).join('')

      // If the data is a string, parse it as JSON
      if (typeof config.data === 'string') {
        try {
          config.data = JSON.parse(config.data)
        } catch (error) {
          console.error('Error parsing config.data as JSON:', error)
          return
        }
      }

      config.data.req_id = generateUuid()
    }

    // Merge the default configuration with the provided configuration
    const mergeConfig = merge(defaultConfig, config)
    return service(mergeConfig)
  }
}

const service = createService()
export const request = createRequest(service)
